package tw.spring.demo.controller;

import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.extern.slf4j.Slf4j;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.mock.mockito.MockBean;
import org.springframework.http.HttpMethod;
import org.springframework.test.context.junit.jupiter.SpringExtension;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.MvcResult;
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;
import org.springframework.test.web.servlet.result.MockMvcResultMatchers;
import tw.spring.demo.model.Article;
import tw.spring.demo.service.ArticleService;

import javax.annotation.Resource;

import static org.mockito.Mockito.when;
import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print;

/**
 * @author: 陈艺博
 * @date: 2021-02-06 16:27
 * @description: 重量级测试， 每次启动时都真实启动一个Service和Spring context 并且可以使用@Resource 进行依赖注入
 **/
@Slf4j
@SpringBootTest//寻找带有@SpringBootApplication的住配置类，用来创建Spring的上下文ApplicationContext，保证测试在上下文环境里运行
//@WebMvcTest(ArticleController.class)//只注入Controller的Bean，加快测试速度 替换@SpringBootTest
@AutoConfigureMockMvc//表示mockMvc对象由spring 依赖注入构建
@ExtendWith(SpringExtension.class)//构造了一个的Servlet容器运行运行环境
//在ExtendWith的AutoConfigureMockMvc注解的共同作用下，启动了SpringMVC的运行容器，并且把项目中所有的@Bean全部都注入进来
class ArticleControllerTest2 {

    //1. 注入MockMvc对象，并将其放入Spring Bean中
    @Resource
    private MockMvc mockMvc;

    //2. 用MockBean伪造模拟一个Service, 不去调用真实的而是去执行when中的返回值
    @MockBean
    private ArticleService articleService;

    //3. 测试方法
    @Test
    public void saveArticle() throws Exception {
        String article = "{\n" +
                "    \"id\": 1,\n" +
                "    \"title\": \"获取文章内容\",\n" +
                "    \"auther\": \"YiBo\",\n" +
                "    \"content\": null,\n" +
                "    \"creatDate\": \"2021-02-04 07:53:12\",\n" +
                "    \"readers\": [\n" +
                "        {\"name\":\"一号读者\", \"age\": 18},\n" +
                "        {\"name\":\"二号读者\", \"age\": 22}\n" +
                "    ]\n" +
                "}";
        ObjectMapper objectMapper = new ObjectMapper();
        Article articleObject = objectMapper.readValue(article, Article.class);

        // 打桩，模拟未完成的Service中的返回值
        when(articleService.saveArticle(articleObject)).thenReturn("ok");

        // 测试代码
        MvcResult result = mockMvc.perform(
                MockMvcRequestBuilders.request(HttpMethod.POST, "/rest/articles/v3")
                        .contentType("application/json")
                        .content(article)
        )
                .andExpect(MockMvcResultMatchers.jsonPath("$.data").value("ok"))
                .andDo(print())
                .andReturn();
        result.getResponse().setCharacterEncoding("UTF-8");
        log.info(result.getResponse().getContentAsString());
    }
}